package cn.rengy.web.framework.wxmp.component.token;

import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import cn.rengy.tpa.wxmp.component.auth.ComponentAccessTokenApi;
import cn.rengy.tpa.wxmp.component.auth.ComponentAccessTokenResponse;
import cn.rengy.tpa.wxmp.component.auth.PreAuthCodeApi;
import cn.rengy.tpa.wxmp.component.auth.PreAuthCodeResponse;
import cn.rengy.tpa.wxmp.component.auth.RefreshTokenResponse;
import cn.rengy.tpa.wxmp.exception.WeChatException;
import cn.rengy.web.framework.sql.DbService;
import cn.rengy.web.framework.wxmp.component.WxComponentAppService;
/**
 * 第三方平台的接口调用令牌的刷新
 * @author rengy
 *
 */
@ConditionalOnProperty(name = "spring.cache.type", havingValue = "redis", matchIfMissing = false)
@Service
public class RedisComponentTokenRefreshService {
	private static Logger logger = LoggerFactory.getLogger(RedisComponentTokenRefreshService.class);
	@Autowired  
	private StringRedisTemplate stringRedisTemplate;
	@Autowired
	private DbService dbService;
	@Autowired
	private WxComponentAppService wxComponentAppService;
	@Autowired
	private ComponentTokenService componentTokenService;
	/**
	 * 刷新平台Token
	 * @param component_app_id
	 * @throws Exception 
	 */
	@Transactional(propagation=Propagation.NESTED)
	public void refresh(String component_app_id) throws WeChatException{
		logger.debug(component_app_id);
		//1.锁定公众号ID
		Map<String,Object> tokenMap=this.dbService.queryForMap("lock_wx_component_token", component_app_id);
		if(tokenMap==null){
			throw new WeChatException("verify_ticket查询为空,无法获取token");
		}
		String key=ComponentTokenService.ACCESS_TOKEN_KEY.concat(component_app_id);
		ValueOperations<String, String> vo=stringRedisTemplate.opsForValue();
		String token=vo.get(key);
		boolean isUpdate=false;
		if(StringUtils.isBlank(token)){
			//已过期或者已删除或者还未加入缓存
			isUpdate=true;
		}else{
			//未过期但是已失效或者是已经更新过了
			//判断更新时间
			Date modify_time=(Date)tokenMap.get("modify_time");
			Date now=new Date();
			//上次更新时间在很短时间内
			if(now.getTime()-modify_time.getTime()<3000){
				//认为已经更新过了，不更新，如果是已失效的则判断不出来
				logger.debug("ComponentAccessToken刚刚更新过了，不重复更新");
			}else{
				isUpdate=true;
			}
		}
		if(isUpdate){
			Map<String,Object> app=wxComponentAppService.getWxComponentApp(component_app_id);
			logger.debug(app.toString());
			String appid=(String)app.get("appid");
			String appsecret=(String)app.get("appsecret");
			String component_verify_ticket=(String)tokenMap.get("verify_ticket");
			ComponentAccessTokenResponse componentAccessTokenResponse=ComponentAccessTokenApi.getComponentAccessToken(appid, appsecret, component_verify_ticket);
			token=componentAccessTokenResponse.getComponent_access_token();
			int expires_in=componentAccessTokenResponse.getExpires_in();
			//加入缓存
			vo.set(key, token);
			//设置过期时间,提前60秒刷新
			if(stringRedisTemplate.expire(key, expires_in-60, TimeUnit.SECONDS)){
				this.dbService.update("update_wx_component_token", token,component_app_id);
			}
		}
	}
	
	/**
	 * 刷新预授权码
	 * @param component_appid 平台appid
	 * @throws Exception 
	 */
	@Transactional(propagation=Propagation.NESTED)
	public void refreshPreAuthCode(String component_appid) throws WeChatException{
		//1.锁定公众号ID
		Map<String,Object> tokenMap=this.dbService.queryForMap("lock_wx_component_token", component_appid);
		if(tokenMap==null){
			throw new WeChatException("verify_ticket查询为空,无法获取token");
		}
		String key=ComponentTokenService.PRE_AUTH_CODE_KEY.concat(component_appid);
		ValueOperations<String, String> vo=stringRedisTemplate.opsForValue();
		String pre_auth_code=vo.get(key);
		boolean isUpdate=false;
		if(StringUtils.isBlank(pre_auth_code)){
			//已过期或者已删除或者还未加入缓存
			isUpdate=true;
		}else{
			//未过期但是已失效或者是已经更新过了
			//判断更新时间
			pre_auth_code=(String)tokenMap.get("pre_auth_code");
			if(StringUtils.isBlank(pre_auth_code)){
				isUpdate=true;
			}else{
				Date modify_time=(Date)tokenMap.get("modify_time");
				Date now=new Date();
				//上次更新时间在很短时间内
				if(now.getTime()-modify_time.getTime()<3000){
					//认为已经更新过了，不更新，如果是已失效的则判断不出来
					logger.debug("pre_auth_code刚刚更新过了，不重复更新");
				}else{
					isUpdate=true;
				}
			}
		}
		if(isUpdate){
			ComponentAccessTokenImpl accessTokenImpl=new ComponentAccessTokenImpl(componentTokenService,component_appid);
			PreAuthCodeApi preAuthCodeApi=new PreAuthCodeApi(accessTokenImpl);
			PreAuthCodeResponse preAuthCodeResponse=preAuthCodeApi.getPreAuthCode(component_appid);
			pre_auth_code=preAuthCodeResponse.getPre_auth_code();
			int ticket_expires_in=preAuthCodeResponse.getExpires_in();
			//ticket加入缓存 提前60秒刷新
			vo.set(key, pre_auth_code);
			if(stringRedisTemplate.expire(key, ticket_expires_in-60, TimeUnit.SECONDS)){
				this.dbService.update("update_component_pre_auth_code",pre_auth_code,component_appid);
			}
		}
	}
		
	/**
	 * 刷新授权方AccessToken
	 * @param appid 授权方appid
	 * @throws WeChatException
	 */
	@Transactional(propagation=Propagation.NESTED)
	public void refreshAuthAccessToken(String authorizer_appid) throws WeChatException{
		//1.锁定
		Map<String,Object> tokenMap=this.dbService.queryForMap("lock_wx_app_token", authorizer_appid);
		if(tokenMap==null){
			throw new WeChatException("wx_app_token查询为空,无法获取token");
		}
		String authorizer_refresh_token=(String)tokenMap.get("authorizer_refresh_token");//刷新令牌
		String component_appid=(String)tokenMap.get("component_appid");
		String key=ComponentTokenService.APP_ACCESS_TOKEN_KEY.concat(authorizer_appid);
		ValueOperations<String, String> vo=stringRedisTemplate.opsForValue();
		String token=vo.get(key);
		boolean isUpdate=false;
		if(StringUtils.isBlank(token)){
			//已过期或者已删除或者还未加入缓存
			isUpdate=true;
		}else{
			//未过期但是已失效或者是已经更新过了
			//判断更新时间
			Date modify_time=(Date)tokenMap.get("modify_time");
			Date now=new Date();
			//上次更新时间在很短时间内
			if(now.getTime()-modify_time.getTime()<3000){
				//认为已经更新过了，不更新，如果是已失效的则判断不出来
				logger.debug("AuthAccessToken刚刚更新过了，不重复更新");
			}else{
				isUpdate=true;
			}
		}
		if(isUpdate){
			ComponentAccessTokenImpl accessTokenImpl=new ComponentAccessTokenImpl(componentTokenService,component_appid);
			RefreshTokenResponse refreshTokenResponse=ComponentAccessTokenApi.refreshAuthorizerAccessToken(accessTokenImpl, component_appid, authorizer_appid, authorizer_refresh_token);
			token=refreshTokenResponse.getAuthorizer_access_token();
			String refresh_token=refreshTokenResponse.getAuthorizer_refresh_token();
			int expires_in=refreshTokenResponse.getExpires_in();
			//ticket加入缓存 提前60秒刷新
			vo.set(key, token);
			if(stringRedisTemplate.expire(key, expires_in-60, TimeUnit.SECONDS)){
				//更新数据库信息 令牌和刷新令牌
				this.dbService.update("update_wx_app_token",token,refresh_token,authorizer_appid);
			}
		}
	}
	
	
	@Transactional(propagation=Propagation.NESTED)
	public void refreshJsApiTicket(String authorizer_appid) throws WeChatException{
		
	}
}
